package com.andnux.android.adapter;

import android.util.ArrayMap;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.viewbinding.ViewBinding;

import com.andnux.android.utils.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

public class BaseAdapter<T, V extends ViewBinding> extends ListAdapter<T, BaseViewHolder<V>> {

    private com.andnux.android.adapter.OnItemClickListener<V> onItemClickListener;
    private com.andnux.android.adapter.OnItemLongClickListener<V> onItemLongClickListener;
    private Map<Integer, Boolean> mArrayMap = new ArrayMap<>();

    public BaseAdapter() {
        super(0);
    }

    @NonNull
    public Map<Integer, Boolean> getArrayMap() {
        return mArrayMap;
    }

    public void setArrayMap(ArrayMap<Integer, Boolean> arrayMap) {
        mArrayMap = arrayMap;
    }

    @SuppressWarnings("all")
    public <M> void addTextChangedListener(EditText text, M object, String key, ChangedCallback<M> callback) {
        try {
            Field field = object.getClass().getDeclaredField(key);
            field.setAccessible(true);
            text.setText(StringUtils.toString(field.get(object)));
            text.setOnEditorActionListener(new TextView.OnEditorActionListener() {
                @Override
                public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                    if (actionId == KeyEvent.ACTION_DOWN || actionId == EditorInfo.IME_ACTION_DONE) {
                        savaValue(v, object, key, callback);
                    }
                    return false;
                }
            });

            text.setOnKeyListener(new View.OnKeyListener() {
                @Override
                public boolean onKey(View view, int keyCode, KeyEvent event) {
                    TextView v = (TextView) view;
                    if (keyCode == KeyEvent.ACTION_DOWN
                            || keyCode == EditorInfo.IME_ACTION_DONE
                            || keyCode == KeyEvent.KEYCODE_BACK
                            || keyCode == EditorInfo.IME_ACTION_GO) {
                        savaValue(v, object, key, callback);
                    }
                    return false;
                }
            });
            text.setOnFocusChangeListener(new View.OnFocusChangeListener() {
                @Override
                public void onFocusChange(View v, boolean hasFocus) {
                    EditText editText = (EditText) v;
                    if (!hasFocus) {
                        savaValue(editText, object, key, callback);
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private <M> void savaValue(TextView v, M object, String key, ChangedCallback<M> callback) {
        try {
            CharSequence s = v.getText();
            Field declaredField = object.getClass().getDeclaredField(key);
            declaredField.setAccessible(true);
            if (declaredField.getType().isAssignableFrom(String.class)) {
                declaredField.set(object, s.toString());
            } else if (declaredField.getType().isAssignableFrom(int.class) || declaredField.getType().isAssignableFrom(Integer.class)) {
                declaredField.set(object, StringUtils.toInt(s));
            } else if (declaredField.getType().isAssignableFrom(double.class) || declaredField.getType().isAssignableFrom(Double.class)) {
                declaredField.set(object, StringUtils.toDouble(s));
            } else if (declaredField.getType().isAssignableFrom(float.class) || declaredField.getType().isAssignableFrom(Float.class)) {
                declaredField.set(object, StringUtils.toFloat(s));
            }
            if (callback != null) {
                callback.onChanged(object);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    @SuppressWarnings("all")
    protected View getItemView(int layoutResId, ViewGroup parent) {
        try {
            Type[] types = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments();
            Class<V> vClass = (Class<V>) types[1];
            Method inflate = vClass.getMethod("inflate", LayoutInflater.class, ViewGroup.class, boolean.class);
            V v = (V) inflate.invoke(null, LayoutInflater.from(parent.getContext()), parent, false);
            return v.getRoot();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return super.getItemView(layoutResId, parent);
    }

    protected int getViewBindingId() {
        return 0;
    }

    public void onBindView(V v, T t, int position, long id) {

    }


    public void onBindView(V v, T t, int position) {

    }

    @NonNull
    @Override
    @SuppressWarnings("all")
    public BaseViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
        try {
            Type[] types = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments();
            Class<V> vClass = (Class<V>) types[1];
            Method inflate = vClass.getMethod("inflate", LayoutInflater.class, ViewGroup.class, boolean.class);
            V v = (V) inflate.invoke(null, LayoutInflater.from(viewGroup.getContext()), viewGroup, false);
            return new BaseViewHolder(v);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return super.onCreateViewHolder(viewGroup, viewType);
    }

    @Override
    public void onBindViewHolder(@NonNull BaseViewHolder<V> vBaseViewHolder, int position) {
        super.onBindViewHolder(vBaseViewHolder, position);
        if (onItemClickListener != null) {
            vBaseViewHolder.itemView.setOnClickListener(v -> onItemClickListener.onItemClick(vBaseViewHolder.v, position, getItemId(position)));
        }
        if (onItemLongClickListener != null) {
            vBaseViewHolder.itemView.setOnLongClickListener(v -> onItemLongClickListener.onItemLongClick(vBaseViewHolder.v, position, getItemId(position)));
        }
        onBindView(vBaseViewHolder.v, getItem(position), position, getItemId(position));
        onBindView(vBaseViewHolder.v, getItem(position), position);
    }

    @Override
    protected void convert(BaseViewHolder<V> vBaseViewHolder, T t) {

    }


    public List<T> getDatas() {
        return getData();
    }

    public void setOnItemClickListener(com.andnux.android.adapter.OnItemClickListener<V> onItemClickListener) {
        this.onItemClickListener = onItemClickListener;
    }

    public void setOnItemLongClickListener(com.andnux.android.adapter.OnItemLongClickListener<V> onItemLongClickListener) {
        this.onItemLongClickListener = onItemLongClickListener;
    }
}
